home *** CD-ROM | disk | FTP | other *** search
- /**
- Company: Eyematic Interfaces
- Project: Shout3D 2.0 Sample Code
- Class: PyramidTestPanel
- Date: April 26, 1999
- Description: Class for panel in which you click-drag to scale some pyramids
- (C) Copyright Eyematic Interfaces, Inc. - 1997-2000 - All rights reserved
- */
-
- package applets;
-
- //Include this in order to be able to work
- //with nodes in the custom_nodes package
- import custom_nodes.*;
-
- import java.applet.*;
- import java.awt.*;
- import java.awt.image.*;
- import java.io.*;
- import java.util.Date;
- import java.net.URL;
- import shout3d.*;
- import shout3d.core.*;
-
- /**
- * PyramidTestPanel
- *
- * Shows how custom nodes can be added to Shout3D
- * and used in applets.
- *
- * This applet creates three Pyramid nodes (a custom node in the
- * custom_nodes directory) and then changes their fields when
- * the user click-drags them.
- *
- *
- * @author Dave Westwood
- * @author Paul Isaacs
- * @author Jim Stewartson
- */
-
- public class PyramidTestPanel extends Shout3DPanel implements DeviceObserver {
-
- // 3 Pyramids to be displayed and manipulated in the scene.
- Pyramid pyramid0, pyramid1, pyramid2;
-
- // For determining which pyramid is clicked with the mouse.
- Picker myPicker;
- Node[] pathToPick;
-
- /**
- * Constructor
- */
- public PyramidTestPanel(Shout3DApplet applet){
- super(applet);
- }
-
- float[] lavender = { .6f, .6f, 1 };
- float[] seafoam = { .6f, 1f, .6f };
- float[] gray = { .6f, .6f, .6f };
-
- float[] pos0 = { -4, 0, 0 };
- float[] pos1 = { 0, 0, 0 };
- float[] pos2 = { 4, 0, 0 };
-
- float[] rot0 = { 0, 1, 0, .8f };
- float[] rot1 = { 0, 1, 0, 0 };
- float[] rot2 = { 0, 1, 0, -.8f };
-
- /**
- *
- * This method is automatically called by the parent class Shout3DPanel
- * at the correct time during initialize().
- *
- * Subclasses should implement this to perform any custom initialization tasks.
- */
- public void customInitialize() {
-
- // Create the three pyramids
- pyramid0 = new Pyramid();
- pyramid1 = new Pyramid();
- pyramid2 = new Pyramid();
-
- // Get a transform for each pyramid, passing in pretty colors
- Transform xf0 = createXf( pyramid0, lavender );
- Transform xf1 = createXf( pyramid1, seafoam );
- Transform xf2 = createXf( pyramid2, gray );
-
- // Position them relative to each other:
- xf0.translation.setValue(pos0);
- xf1.translation.setValue(pos1);
- xf2.translation.setValue(pos2);
- xf0.rotation.setValue(rot0);
- xf1.rotation.setValue(rot1);
- xf2.rotation.setValue(rot2);
-
- // Add to the scene
- Node[] newKids = new Node[3];
- newKids[0] = xf0;
- newKids[1] = xf1;
- newKids[2] = xf2;
- getScene().addChildren(newKids);
-
- // Move the camera back
- Viewpoint myVP = (Viewpoint) getCurrentBindableNode("Viewpoint");
- myVP.position.getValue()[2] = 10;
- //notify
- myVP.position.setValue(myVP.position.getValue());
-
- // Allocate the picker
- myPicker = getNewPicker();
-
- //Watch for mouse events to do the picking.
- this.addDeviceObserver(this, "MouseInput", null);
- //Register to watch rendering. We'll want to change pyramid
- //fields between renders so that field don't change during
- //mid-multithreaded-render
- getRenderer().addRenderObserver(this,null);
-
- //Call the parent class
- super.customInitialize();
- }
-
- /**
- * Finalize
- */
- protected void finalize()throws Throwable {
- getRenderer().removeRenderObserver(this);
- this.removeDeviceObserver(this, "MouseInput");
- super.finalize();
- }
-
- Node pathTail;
- Pyramid selectedPyramid;
- float startWidth, startHeight, startDepth;
- int startCursorX, startCursorY;
- boolean waitingToChangeFields = false;
- float nextWidth = 1;
- float nextHeight = 1;
- float nextDepth = 1;
-
- /**
- * Called when Mouse input is received.
- *
- * On mouse DOWN, checks for selection of one of the pyramids.
- * Remembers which pyramid, and starting cursor location.
- *
- * On mouse DRAG, scales the selected pyramid.
- * Horizontal motion scales width,depth.
- * Vertical motion scales height.
- *
- */
- public boolean onDeviceInput(DeviceInput di, Object userData){
- //No need to check type of deviceInput, only registered for Mouse Input.
- MouseInput mi = (MouseInput) di;
- if (mi.which == MouseInput.DOWN){
-
- // Perform a pick and see if one of the pyramids was picked.
- //
- selectedPyramid = null;
- pathToPick = myPicker.pickClosest(mi.x,mi.y);
- if (pathToPick!=null && pathToPick.length > 0){
- pathTail = pathToPick[pathToPick.length-1];
- if (pathTail instanceof Pyramid){
- selectedPyramid = (Pyramid) pathTail;
-
- startCursorX = mi.x;
- startCursorY = mi.y;
- startWidth = selectedPyramid.width.getValue();
- startHeight = selectedPyramid.height.getValue();
- startDepth = selectedPyramid.depth.getValue();
-
- //This input was used
- return true;
- }
- }
- }
- else if (mi.which == MouseInput.DRAG){
- // Based on mouse motion, change fields of currentPyramid.
-
- // Width and depth change equally with horizontal motion,
- // Height changes with vertical motion.
- // Change by 1 unit every 100 pixels
- nextWidth = startWidth + (float)(mi.x-startCursorX)/100;
- nextHeight = startHeight - (float)(mi.y-startCursorY)/100;
- nextDepth = startDepth + (float)(mi.x-startCursorX)/100;
-
- // Clamp values to be > 0.1
- if (nextWidth < 0.1) nextWidth = 0.1f;
- if (nextHeight < 0.1) nextHeight = 0.1f;
- if (nextDepth < 0.1) nextDepth = 0.1f;
-
- // Don't set the field values now.
- // Let them be set during onPreRender so that
- // the field change occurs between renders.
- waitingToChangeFields = true;
-
- // Used the input
- return true;
- }
- //Did not care about this input
- return false;
- }
-
- /**
- * Changing the fields should be done between renders.
- * This is because rendering happens in a different thread,
- * and updating the fields during a render can cause unpleasant
- * flashing.
- *
- * Note that no onPostRender() method is implemented in this class,
- * even though it is required for all classes implementing RenderObserver.
- * This is because the super class implements RenderObserver fully
- * and onPostRender is inherited.
- * Hence this class needs only to override the onPreRender() method,
- * making sure to call super.onPreRender(r,userData) within the body
- * of the method.
- */
- public void onPreRender(Renderer r, Object userData){
- super.onPreRender(r, userData);
- if (selectedPyramid != null && waitingToChangeFields){
- selectedPyramid.width.setValue(nextWidth);
- selectedPyramid.height.setValue(nextHeight);
- selectedPyramid.depth.setValue(nextDepth);
- waitingToChangeFields = false;
- }
- }
-
- Transform createXf( Pyramid pyr, float[/*3*/] color ) {
- Material newMat = new Material();
- newMat.diffuseColor.setValue(color);
-
- Appearance newApp = new Appearance();
- newApp.material.setValue(newMat);
-
- shout3d.core.Shape newShape = new shout3d.core.Shape();
- newShape.geometry.setValue(pyr);
- newShape.appearance.setValue( new Appearance[] { newApp });
-
- Transform newXf = new Transform();
- Node[] kids = new Node[1];
- kids[0] = newShape;
- newXf.addChildren(kids);
- return newXf;
- }
- }
-